/* $RCSFile: GenericCRMBindable.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/GenericCRMBindable.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;

using CrmSdk;


namespace AddonNice.CRMWrapper 
{

    /// <summary>
    /// Provides an IList that can be bound directly to a standard .NET Data Grid
    /// </summary>
    public class GenericBindableList<T> : IList<T> where T:DynEntity
    {
        List<T>  _dynEntities       =   new List<T>();
        bool    _IsReadOnly         =   true;

        string _entityName          = string.Empty;
        CRMWrapperBase _wrapper         = null;

        public CRMWrapperBase wrapper
        {
            get { return _wrapper; }
        }

        public string entityName
        {
            get { return _entityName; }
        }
        /// <summary>
        /// Get the <T> config to build the attributes table
        /// </summary>
        EntityConfig _TConfig = null;
        public EntityConfig TConfig
        {
            get
            {
                if (_TConfig == null)
                {
                    /*
                    bool isAdmin                = true;
                    EntityInternalItems vflag        = EntityInternalItems.IncludeAttributes;
                    InternalDisplayMasks validForForm   = InternalDisplayMasks.None | InternalDisplayMasks.PrimaryName | InternalDisplayMasks.ValidForForm | InternalDisplayMasks.ValidForGrid | 
                            InternalDisplayMasks.ValidForAdvancedFind | InternalDisplayMasks.RequiredForForm | InternalDisplayMasks.RequiredForGrid;
                    AttributeInternalRequiredLevel requiredLevel   = AttributeInternalRequiredLevel.None | AttributeInternalRequiredLevel.ReadOnly 
                        | AttributeInternalRequiredLevel.Recommended | AttributeInternalRequiredLevel.Required | AttributeInternalRequiredLevel.SystemRequired;

                    _TConfig = new EntityConfig(
                        wrapper,
                        entityName,
                        vflag, requiredLevel,
                        isAdmin, validForForm);
                     */
                    _TConfig    =   new EntityConfig(wrapper,entityName);
                    if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"GenericBindableList<T> TConfig created vflag: {0},isAdmin: {1}, DisplayMask: [{2}] ",
                            new object[] { _TConfig.entityFlags, true, _TConfig.DisplayMask}),CRMTraceSwitch.Sw.Info);
                }
                return _TConfig;
            }
        }


        public GenericBindableList(CRMWrapperBase w, InternalBusinessEntityCollection crmEntities) 
        {
            // Standard MetaData Service Setup

            // Get the name of the entity
            // Note: We have to convert this to lower because RetrieveEntityMetadata expects the schema name
            _entityName         =   w.Util.ExtractEntityName(crmEntities);
            _wrapper            =   w;


            PropertyDescriptorCollection _columnDescriptors             =   null;
            // Cache locals
            //_entities = crmEntities.BusinessEntities;
            w.Util.ExecForEachDynamicEntity(crmEntities,delegate(InternalDynamicEntity bu)
                {
                T ob = (T)Activator.CreateInstance(typeof(T), new object[] {w,bu,_columnDescriptors});
                ((DynEntity)ob).EntityMData =   TConfig.entityMetaData;
                _columnDescriptors = ((DynEntity)ob).PropertyDescriptorCollection;
                _dynEntities.Add(ob);
                return true; // continue
                }
                );
        }

        #region GenericBindableListEnumerator Class

        /// <summary>
        /// Enumerator for the Universal Entity List
        /// </summary>
        class GenericBindableListEnumerator : System.Collections.IEnumerator, System.Collections.Generic.IEnumerator<T> 
        {
            private GenericBindableList<T> _entityList;
            private int _index = -1;

            internal GenericBindableListEnumerator(GenericBindableList<T> entityList) {
                _entityList = entityList;
            }

            public void Dispose()
            {
            }

            public bool MoveNext() 
            {
                // If there are no records or moving forward would go past the total
                // number of available records, return false.
                if (_entityList._dynEntities.Count == 0 || (_index + 1) >= _entityList._dynEntities.Count) {
                    return false;
                }
                _index++;
                return true;
            }

            public void Reset() {
                _index = -1;
            }

            Object IEnumerator.Current {
                get
                {
                    if (_index < 0)
                    {
                        throw new CRMWrapperException("CRMBindable: Current not set");
                    }
                    try
                    {
                        return _entityList[_index];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }

                }
            }

            public T Current
            {
                get {
                    return _entityList[_index];
                }
            }
        }

        #endregion

        #region IList<T> Membres


        public T this[int index] {
            get {
                return  _dynEntities[index];
            }
            set {
                _dynEntities[index] =   value;
            }
        }

        public int IndexOf(T item)
        {
            return  _dynEntities.IndexOf(item);
        }

        public void Insert(int index, T item)
        {
            _dynEntities.Insert(index,item);
        }

        #endregion

        #region ICollection<T> Membres

        public void Add(T item)
        {
            _dynEntities.Add(item);
        }

        public bool Contains(T item)
        {
            return _dynEntities.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            _dynEntities.CopyTo(array,arrayIndex);
        }

        public bool Remove(T item)
        {
            return _dynEntities.Remove(item);
        }

        #endregion

        #region IEnumerable<T> Membres

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return new GenericBindableListEnumerator(this);
        }

        #endregion


        #region IEnumerable Membres
        IEnumerator IEnumerable.GetEnumerator() {
            return new GenericBindableListEnumerator(this);
        }
        #endregion

        #region IList<T> Membres


        public void RemoveAt(int index)
        {
            _dynEntities.RemoveAt(index);
        }

        #endregion

        #region ICollection<T> Membres


        public void Clear()
        {
            _dynEntities.Clear();
        }

        public int Count
        {
            get { return _dynEntities.Count; }
        }
        public bool IsReadOnly
        {
            get { return _IsReadOnly; }
            set
            {
                _IsReadOnly = value;
            }
        }
        #endregion
    }
   }